/****************************************************************************
*                                                                           *
* Copyright (c) Ionescu M. Marius. All rights reserved(2010).               *
*                                                                           *
****************************************************************************/

using System;
using System.IO;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Serialization;
using System.Web;
using System.Xml;
using System.Xml.Schema;

namespace XMLTools
{
	public class XMLValidator
	{
		int ErrorsCount = 0;
		System.Text.StringBuilder ErrorMessage = new System.Text.StringBuilder("");
		string _validatorMessageFile = "";

		public XMLValidator(string validatorMessageFile)
		{
			_validatorMessageFile = validatorMessageFile;
		}

		public void ValidationHandler(object sender, ValidationEventArgs args)
		{
			ErrorMessage.Append("\r\n");
			ErrorMessage.Append(args.Message);
			ErrorsCount++;
		}

		public void Validate(string strXMLDoc, string urlXSD)
		{
			try
			{
				// Text reader object
				XmlTextReader tr  = new XmlTextReader(strXMLDoc);
                XmlSchemaCollection xsc = new XmlSchemaCollection();
				xsc.Add(null, urlXSD);

				// XML validator object

				XmlValidatingReader vr = new XmlValidatingReader(tr);

				vr.Schemas.Add(xsc);

				// Add validation event handler

				vr.ValidationType = ValidationType.Schema;
                vr.ValidationEventHandler += new ValidationEventHandler(ValidationHandler);

				// Validate XML data

				while(vr.Read());

				vr.Close();

				// Raise exception, if XML validation fails
				if (ErrorsCount > 0)
				{
					SaveValidationErrorToFile();
					throw new XMLValidationException(string.Format("XML validation fails.\r\n {0}", ErrorMessage.ToString()));
				}
			}
			catch(XMLValidationException)
			{
				throw;	
			}
			catch(Exception)
			{
				throw;
			}
		}

		
		public void Validate(Stream stream, string urlXSD)
		{
			try
			{
				stream.Position = 0;
				// Text reader object
				XmlTextReader tr  = new XmlTextReader(stream);
				XmlSchemaCollection xsc = new XmlSchemaCollection();
				xsc.Add(null, urlXSD);
				
				// XML validator object

				XmlValidatingReader vr = new XmlValidatingReader(tr);

				vr.Schemas.Add(xsc);

				// Add validation event handler

				vr.ValidationType = ValidationType.Schema;
				vr.ValidationEventHandler += new ValidationEventHandler(ValidationHandler);

				// Validate XML data

				while (vr.Read()) ;

				vr.Close();

				// Raise exception, if XML validation fails
				if (ErrorsCount > 0)
				{
					SaveValidationErrorToFile();
					throw new XMLValidationException(string.Format("XML validation fails:\r\n {0}", ErrorMessage.ToString()));
				}

				// XML Validation succeeded
				//Console.WriteLine("XML validation succeeded.\r\n");
			}
			catch(XMLValidationException)
			{
				throw;
			}
			catch(Exception)
			{
				// XML Validation failed
				throw;
			}
		}

		
		private void SaveValidationErrorToFile()
		{
			FileStream fileStream;

			// TODO: Create directory, if necessary
			try
			{
				fileStream = new FileStream(_validatorMessageFile, FileMode.Append);
			}
			catch (DirectoryNotFoundException)
			{
				Directory.CreateDirectory((new FileInfo(_validatorMessageFile)).DirectoryName);
				fileStream = new FileStream(_validatorMessageFile, FileMode.Append);
			}

			StreamWriter writer = new StreamWriter(fileStream);
			try
			{
				writer.Write(string.Concat(DateTime.Now.Date.ToString("yyyy-MM-dd hh:mm:ss"), "\r\n", ErrorMessage.ToString(), "\r\n"));
			}
			catch { }
			finally
			{
				try
				{
					writer.Close();
				}
				catch {}
			}
		}
	}

	public class XMLValidationException : Exception
	{
		public XMLValidationException(string message):base(message){}
		public XMLValidationException(string message, Exception inner):base(message, inner){}
		public XMLValidationException(SerializationInfo info, StreamingContext context): base(info, context){}
	}
}